home *** CD-ROM | disk | FTP | other *** search
/ ADA Programming Guide / ADA Programming Guide.iso / ada_gwu / predef4.c < prev    next >
C/C++ Source or Header  |  1996-01-30  |  24KB  |  895 lines

  1. /*
  2.  * Copyright (C) 1985-1992  New York University
  3.  * 
  4.  * This file is part of the Ada/Ed-C system.  See the Ada/Ed README file for
  5.  * warranty (none) and distribution info and also the GNU General Public
  6.  * License for more details.
  7.  
  8.  */
  9. /*    +---------------------------------------------------+
  10.       |                                                   |
  11.       |          I N T E R P     P R E D E F S            |
  12.       |         Part 4: Input/Output Procedures           |
  13.       |                  (C Version)                      |
  14.       |                                                   |
  15.       |   Adapted From Low Level SETL version written by  |
  16.       |                                                   |
  17.       |                  Monte Zweben                     |
  18.       |               Philippe Kruchten                   |
  19.       |               Jean-Pierre Rosen                   |
  20.       |                                                   |
  21.       |    Original High Level SETL version written by    |
  22.       |                                                   |
  23.       |                   Clint Goss                      |
  24.       |               Tracey M. Siesser                   |
  25.       |               Bernard D. Banner                   |
  26.       |               Stephen C. Bryant                   |
  27.       |                  Gerry Fisher                     |
  28.       |                                                   |
  29.       |              C version written by                 |
  30.       |                                                   |
  31.       |               Robert B. K. Dewar                  |
  32.       |                                                   |
  33.       +---------------------------------------------------+
  34. */
  35.  
  36. /*  This module contains routines for the implementation of some of
  37.  *  the predefined Ada packages and routines, namely SEQUENTIAL_IO,
  38.  *  DIRECT_IO, TEXT_IO, and CALENDAR. Part 4 contains the initialization
  39.  *  and termination routines for predef, and the basic I/O routines
  40. */
  41.  
  42. #include <stdlib.h>
  43. #include <string.h>
  44. #ifdef IBM_PC
  45. #include <io.h>
  46. #endif
  47. #include "ipredef.h"
  48. #include "miscp.h"
  49. #include "predefp.h"
  50.  
  51. static void check_ifile_closed(int *);
  52. static void check_xfile_closed(char *);
  53. static void open_file();
  54. #ifdef IBM_PC
  55. #undef putc
  56. #define putc(A, B) fputc((A),(B));fflush(B)
  57. #endif
  58. #ifdef GWUMON
  59. #undef putc
  60. #define putc(A, B) CWK_PUTC((A),(B))
  61. #endif
  62. #ifdef DEBUG_PREDEF
  63. static void gchar(char *, int);
  64. static void pchar(char *, int);
  65. #endif
  66.  
  67. /* AFCB for STANDARD_IN_FILE */
  68.  
  69. static struct afcb  in_afcb = {
  70.  
  71.     0,                          /* file descriptor for standard input */
  72.     "",                         /* file name(null) */
  73.     "",                         /* form string(null) */
  74.     TIO_IN_FILE,                /* mode, TEXT_IO input */
  75.     0, 0, 0,                    /* unused DIRECT_IO fields */
  76.     1,                          /* page number */
  77.     1,                          /* line number */
  78.     1,                          /* column number */
  79.     0,                          /* unbounded line length */
  80.     0,                          /* unbounded page length */
  81.     0, "  "                    /* look ahead */
  82. };
  83.  
  84. #ifdef IBM_PC
  85. /* keep track of last character read from stdin so can detect whether we
  86.  * need to flush what is left there before exiting
  87.  */
  88. static int last_char_input = EOF;
  89. #endif
  90.  
  91. /* AFCB for STANDARD_OUT_FILE */
  92.  
  93. static struct afcb  out_afcb = {
  94.  
  95.     0,                          /* file descriptor for standard input */
  96.     "",                         /* file name(null) */
  97.     "",                         /* form string(null) */
  98.     TIO_OUT_FILE,               /* mode, TEXT_IO output */
  99.     0, 0, 0,                    /* unused DIRECT_IO fields */
  100.     1,                          /* page number */
  101.     1,                          /* line number */
  102.     1,                          /* column number */
  103.     0,                          /* unbounded line length */
  104.     0,                          /* unbounded page length */
  105.     0, "  "                    /* look ahead */
  106. };
  107.  
  108. /* Procedure to initialize input/output data structures */
  109.  
  110. void initialize_predef()                     /*;initialize_predef*/
  111. {
  112.     /* Clear temporary file list, and clear AFCB vector */
  113.  
  114.     tfiles = 0;
  115.     for (filenum = 1; filenum <= MAXFILES; filenum++)
  116.         afcbs[filenum - 1] = 0;
  117.  
  118.     /* Setup references for current and standard files */
  119.  
  120.     current_in_file = 1;
  121.     current_in_file_saved = 1;
  122.     standard_in_file = 1;
  123.     afcbs[0] = &in_afcb;
  124.     filenum = 1;
  125.     IOFDESC = stdin;
  126.     CHARS = 0;
  127.  
  128.     current_out_file = 2;
  129.     current_out_file_saved = 2;
  130.     standard_out_file = 2;
  131.     afcbs[1] = &out_afcb;
  132.     filenum = 2;
  133.     IOFDESC = stdout;
  134.  
  135.     /* Set standard exception signalled on bad data (changed temporarily
  136.      * to CONSTRAINT_ERROR when TEXT_IO routines are called directly from
  137.      * the main interpretor for the IMAGE attribute.
  138.      */
  139.  
  140.     data_exception = DATA_ERROR;
  141. }
  142.  
  143.  
  144. /* CHECK_OPENED_OK */
  145.  
  146. /* Checks that an fopen succeeded, raise USE_ERROR if not */
  147.  
  148. void check_opened_ok()                                   /*;check_opened_ok*/
  149. {
  150.     if (IOFDESC == NULL)
  151.         predef_raise(USE_ERROR, "Error opening or resetting file");
  152. }
  153.  
  154. /* CHECK_IFILE_CLOSED */
  155.  
  156. /* Checks that the file object stored at file_ptr is closed */
  157.  
  158. static void check_ifile_closed(int *file_ptr)           /*;check_ifile_closed*/
  159. {
  160.     int     file_val;
  161.  
  162.     file_val = *file_ptr;
  163.     if (file_val != 0)
  164.         predef_raise(STATUS_ERROR, "File not closed");
  165. }
  166.  
  167. /* CHECK_XFILE_CLOSED */
  168.  
  169. /* Checks that no external file with a matching name is currently open */
  170.  
  171. static void check_xfile_closed(char *fname)             /*;check_xfile_closed*/
  172. {
  173.     int     i;
  174.     for (i = 1; i <= MAXFILES; i++) {
  175.         if (afcbs[i - 1] == NULL) continue;
  176.         if (strcmp(fname, afcbs[i - 1] -> io_fname) == 0 &&
  177.           afcbs[i - 1] -> io_fdesc != NULL) {
  178.             predef_raise(USE_ERROR, "File already open");
  179.         }
  180.     }
  181. }
  182.  
  183. /* CHECK_FILE_OPEN */
  184.  
  185. /* Check if the current file is open or not. If the file is not open,
  186.   * then STATUS_ERROR is raised. Otherwise control returns normally.
  187. */
  188.  
  189. void check_file_open()                                       /*;check_file_open*/
  190. {
  191.     if (filenum == 0)
  192.         predef_raise(STATUS_ERROR, "File not open");
  193. }
  194.  
  195. /* If the current file is not open, then STATUS_ERROR is raised. If
  196.  * the file is open, then the mode is checked against the argument which
  197.  * is the desired mode for the operation. If it does not match, then
  198.  * MODE_ERROR is raised, otherwise control returns normally.
  199.  */
  200.  
  201. void check_status(int c_mode)                                /*;check_status*/
  202. {
  203.     check_file_open();
  204.     if (IOMODE != c_mode)
  205.         predef_raise(MODE_ERROR, "Incorrect file status");
  206. }
  207.  
  208. /*  Routine called by the OPEN and CREATE portions of the PREDEF procedure
  209.  *  to perform common data structure operations for TEXT_IO operations.
  210.  *  The operation in opn is 'C' for a create and 'O' for an open.
  211.  */
  212.  
  213. void open_textio(char opn)                       /*;open_textio*/
  214. {
  215.     open_file();
  216.  
  217. #ifdef SYSTEM_V
  218.     if (strlen(IOFNAME) > 14) predef_raise(NAME_ERROR,"Invalid file name");
  219. #endif
  220.  
  221.     if (opn == 'C') {
  222.         IOFDESC = fopen_txt(IOFNAME, "w");
  223.         if (IOFDESC == NULL) predef_raise(NAME_ERROR,"Invalid file name");
  224.         if (IOMODE == SIO_IN_FILE) {
  225.             fclose(IOFDESC);
  226.             IOFDESC = fopen_txt(IOFNAME, "r");
  227.             check_opened_ok();
  228.         }
  229.     }
  230.     else {                      /* opn == 'O' */
  231.         /*
  232.         * According to AI-00048: 
  233.         * Opening a file with IN_FILE mode which is the default output file 
  234.         * will raise MODE_ERROR. 
  235.         * Opening a file with OUT_FILE mode which is the default input file 
  236.         * will raise MODE_ERROR.
  237.         * The values to be checked is in current_in_file_saved and
  238.         * current_out_file_saved which are copies of the file numbers
  239.         * associated with the default files. These copies must be used
  240.         * because when the default files are closed their filenums saved
  241.         * in current_XXX_file are set to zero and therefore lost for this
  242.         * check.
  243.         */
  244.         if (filenum == current_in_file_saved && IOMODE == TIO_OUT_FILE)
  245.             predef_raise(MODE_ERROR,"File is default in file");
  246.         if (filenum == current_out_file_saved && IOMODE == TIO_IN_FILE)
  247.             predef_raise(MODE_ERROR,"File is default out file");
  248.         IOFDESC = fopen_txt(IOFNAME, "r");
  249.         if (IOFDESC == NULL) predef_raise(NAME_ERROR,"File not found");
  250.         if (IOMODE == TIO_IN_FILE)
  251.             CHARS = 0;
  252.         else {
  253.             fclose(IOFDESC);
  254.             IOFDESC = fopen_txt(IOFNAME, "w");
  255.             check_opened_ok();
  256.         }
  257.     }
  258.  
  259.     PAGE = 1;
  260.     LINE = 1;
  261.     COL = 1;
  262.     LINE_LENGTH = 0;
  263.     PAGE_LENGTH = 0;
  264.  
  265.     *get_argument_ptr(0) = filenum;
  266. }
  267.  
  268. /* LOAD_LOOK_AHEAD */
  269.  
  270. /* This procedure loads the lookahead for a TEXT_IO input file, leaving
  271.  * CHARS set to 3 (unless the file is less than 3 bytes long), and CHAR1
  272.  * CHAR2 and CHAR3 containing the initial characters of the file. A special
  273.  * exception occurs when the standard input file is the keyboard in which case
  274.  * we only read 1 character because of interactive  I/O except when 
  275.  * load_look_ahead is called in the case of END_OF_FILE where we want to 
  276.  * read 2 characters to check for the EOT character. The parameter to this
  277.  * routine end_of_file_flag is TRUE when processing for and END_OF_FILE
  278.  * situation and is FALSE otherwise.
  279. */
  280.  
  281. void load_look_ahead(int end_of_file_flag)            /*;load_look_ahead*/
  282. {
  283.     int c;
  284.  
  285.     /* Load first character of look ahead */
  286.  
  287.     if (CHARS == 0) {
  288.         CHAR2 = CHAR3 = 0;
  289. #ifdef GWUMON
  290.         {    
  291.         static int PUT_NEW_LINE = 1;
  292.  
  293.         c = fgetc(IOFDESC);
  294.         if (PUT_NEW_LINE)
  295.         {
  296.             CWK_MOVE_INPUT( IOFDESC );
  297.             PUT_NEW_LINE = 0;
  298.         }
  299.         if (c == 10)
  300.             PUT_NEW_LINE = 1;
  301.         }
  302. #else
  303.         c = fgetc(IOFDESC);
  304. #endif
  305.  
  306. #ifdef IBM_PC
  307.         if (IOFDESC == stdin) last_char_input = c;
  308. #endif
  309.         gchar("load_look 1", c);
  310.         if (c == EOF) {
  311.             CHAR1 = 0;
  312.             return;
  313.         }
  314.         else {
  315.             CHAR1 = c;
  316.             CHARS = 1;
  317.         }
  318.     }
  319.  
  320.         /* In the case where reading from the keyboard do not read more than
  321.          * 1 character unless you are processing an end_of_file test.
  322.          */
  323.     if (isatty(fileno(IOFDESC)) && (!end_of_file_flag)) return;
  324.     /* Load second character of look ahead */
  325.  
  326.     if (CHARS == 1) {
  327.         CHAR3 = 0;
  328.         c = fgetc(IOFDESC);
  329. #ifdef IBM_PC
  330.         if (IOFDESC == stdin) last_char_input = c;
  331. #endif
  332.         gchar("load_look 2",c);
  333.         if (c == EOF) {
  334.             CHAR2 = 0;
  335.             return;
  336.         }
  337.         else {
  338.             CHAR2 = c;
  339.             CHARS = 2;
  340.         }
  341.     }
  342.  
  343.     /* Leave lookahead with at most two characters loaded if */
  344.         /* standard input is the keyboard.                       */
  345.  
  346.     if (!isatty(fileno(IOFDESC))) {
  347.         /* Load third character of look ahead */
  348.  
  349.         if (CHARS == 2) {
  350.             c = fgetc(IOFDESC);
  351.             gchar("load_look 3",c);
  352.             if (c == EOF) {
  353.                 CHAR3 = 0;
  354.                 return;
  355.             }
  356.             else {
  357.                 CHAR3 = c;
  358.                 CHARS = 3;
  359.             }
  360.         }
  361.     }
  362. }
  363.  
  364. /* CLOSE_TEXTIO */
  365.  
  366. /*  This routine is called by the CLOSE portion of the PREDEF procedure to
  367.  *  perform common data structure operations for text_io. Perform various
  368.  *  actions based on whether this is an input or output file.
  369.  */
  370.  
  371. void close_textio()                                          /*;close_text_io*/
  372. {
  373.     if (IOMODE == TIO_OUT_FILE) {
  374.  
  375.         /* Simulate effect of NEW_PAGE unless current page is terminated */
  376.  
  377.         if (!PAGE_TERMINATED) {
  378.             if (COL > 1 ||(COL == 1 && LINE == 1))
  379.                 put_line();
  380.             put_page();
  381.         }
  382.     }
  383.  
  384.     /* Sever the association between the given file and its associated
  385.      * external file.   The given file is left closed.  Do not perform
  386.      * system closes on the standard input and output files.
  387.      */
  388.  
  389.     if (filenum != standard_in_file && filenum != standard_out_file)
  390.         close_file();
  391.  
  392.     /* If the file being closed is one of the default files, set the default
  393.      * file indicator to zero to indicate that the file is closed.
  394.      */
  395.  
  396.     if (filenum == current_in_file)
  397.         current_in_file = 0;
  398.     else if (filenum == current_out_file)
  399.         current_out_file = 0;
  400. }
  401.  
  402. /*  TEXT_IO Line Management Procedures */
  403.  
  404. /* GET_CHAR */
  405.  
  406. /*  Procedure to get the next character from the current text input file.
  407.  *  If no character is available, then END_ERROR is raised.
  408.  */
  409.  
  410. char get_char()                                                     /*;get_char*/
  411. {
  412.     char    c;                          /* character read */
  413.  
  414.     /* Load look ahead and check for no more characters */
  415.  
  416.     load_look_ahead(FALSE);
  417.     if (CHARS == 0)
  418.         predef_raise(END_ERROR, "End of file on TEXT_IO input");
  419.     c = CHAR1;
  420.  
  421.     /* Update lookahead */
  422.  
  423.     CHAR1 = CHAR2;
  424.     CHAR2 = CHAR3;
  425.     CHAR3 = 0;
  426.     CHARS--;
  427.  
  428.     /* Update PAGE and LINE counters if page mark or line feed read */
  429.  
  430.     if (c == PAGE_MARK) {
  431.         PAGE += 1;
  432.         LINE = 1;
  433.         COL = 1;
  434.     }
  435.     else if (c == LINE_FEED) {
  436.         LINE += 1;
  437.         COL = 1;
  438.     }
  439.     else
  440.         COL += 1;
  441.     if (c > 127)
  442.         predef_raise(DATA_ERROR, "Character > 127 for TEXT_IO input");
  443.     gchar("get_char",c);
  444.     return c;
  445. }
  446.  
  447. /* SKIP_LINE */
  448.  
  449. /* Procedure to perform SKIP_LINE operation for a spacing of 1 line. Skips
  450.  * characters up to and including next line terminator. Also skips any
  451.  * page marks following this line terminator (there should normally be at
  452.  * most one in standard format files, but we just skip past several if
  453.  * we find them present).
  454. */
  455.  
  456. void skip_line()                                                 /*;skip_line*/
  457. {
  458.     for (;;) {
  459.         load_look_ahead(FALSE);
  460.         if (get_char() == LINE_FEED)
  461.             break;
  462.     }
  463.  
  464.     /* ignore page marks for standard input. */
  465.  
  466.     if (IOFDESC == stdin) return;
  467.  
  468.     for (;;) {
  469.         load_look_ahead(FALSE);
  470.         if (CHAR1 != PAGE_MARK) break;
  471.         get_char();
  472.     }
  473. }
  474.  
  475. /* PUT_BLANKS */
  476.  
  477. /* Procedure to write n blanks to current text file. There is no check for
  478.  * line overflow, it is assumed that the caller has checked line overflow.
  479.  */
  480.  
  481. void put_blanks(int n)                                           /*;put_blanks*/
  482. {
  483.     while (n--) {
  484.         pchar("put_blanks",' ');
  485.         putc(' ', IOFDESC);
  486.     }
  487. }
  488.  
  489. /* PUT_CHAR */
  490.  
  491. /* Procedure to write 1 character to current text file. Functions exactly
  492.  * as if writing a one character string(see PUT_STRING function)
  493.  */
  494.  
  495. void put_char(char c)                                             /*;put_char*/
  496. {
  497.     if (BOUNDED_LINE_LENGTH && COL > LINE_LENGTH )
  498.         put_line();
  499.     pchar("put_char",c);
  500.     putc(c, IOFDESC);
  501.     COL++;
  502. }
  503.  
  504. /* PUT_LINE */
  505.  
  506. /* This procedure outputs a line feed to the current text file */
  507.  
  508. void put_line()                                                      /*;put_line*/
  509. {
  510.     pchar("put_line",LINE_FEED);
  511.     putc(LINE_FEED, IOFDESC);
  512.     COL = 1;
  513.     if (BOUNDED_PAGE_LENGTH && LINE >= PAGE_LENGTH)
  514.         put_page();
  515.     else LINE += 1;
  516. }
  517.  
  518. /* PUT_PAGE */
  519.  
  520. /* Procedure to write page mark to current text file */
  521.  
  522. void put_page()                                                  /*;put_page*/
  523. {
  524.     pchar("put_page",PAGE_MARK);
  525.     putc(PAGE_MARK, IOFDESC);
  526.     PAGE += 1;
  527.     LINE = 1;
  528.     COL = 1;
  529. }
  530.  
  531. /* Put a string into the output file, performing line breaks as needed */
  532.  
  533. void put_string(char *s)                                       /*;put_string*/
  534. {
  535.     int     left_in_string;             /* chars left in string */
  536.     int     left_in_line;               /* chars left in current line */
  537.  
  538.     left_in_string = strlen(s);
  539.  
  540.     if (UNBOUNDED_LINE_LENGTH) {
  541.         COL += left_in_string;
  542.         while (left_in_string--) {
  543.             pchar("put_string 1",*s);
  544.             putc(*s++,IOFDESC);
  545.         }
  546.     }
  547.  
  548.     else {
  549.         while(left_in_string != 0) {
  550.             left_in_line = LINE_LENGTH - COL + 1;
  551.             if (left_in_line <= 0) {
  552.                 put_line();
  553.                 left_in_line = LINE_LENGTH;
  554.             }
  555.  
  556.             if (left_in_string <= left_in_line) {
  557.                 COL += left_in_string;
  558.                 while (left_in_string) {
  559.                     pchar("put_string 2",*s);
  560.                     putc(*s++,IOFDESC);
  561.                     /* left_in_string should never become negative */
  562.                     left_in_string--;
  563.                 }
  564.             }
  565.             else {
  566.                 left_in_string -= left_in_line;
  567.                 while (left_in_line--) {
  568.                     pchar("put_string 3",*s);
  569.                     putc(*s++,IOFDESC);
  570.                 }
  571.                 put_line();
  572.             }
  573.         }
  574.     }
  575. }
  576.  
  577.  
  578. /* PUT_BUFFER */
  579.  
  580. /*  This routine writes an item(passed in as a string) with appropriate
  581.  *  blank padding. The second parameter is the desired width, and the third
  582.  *  parameter is 'L' for leading blank padding and 'T' for trailing padding.
  583.  */
  584.  
  585. void put_buffer(char *buffer, int width, char padtype)          /*;put_buffer*/
  586. {
  587.     int     slength, tlength;
  588.     int n;
  589.  
  590.     slength = strlen(buffer);
  591.     if (slength < width)
  592.         tlength = width;
  593.     else {
  594.         tlength = slength;
  595.         padtype = ' ';
  596.     }
  597.  
  598.     /* Ensure the buffer size does not exceed the line length */
  599.  
  600.     if (BOUNDED_LINE_LENGTH) {
  601.         if (tlength > LINE_LENGTH)
  602.             predef_raise(LAYOUT_ERROR, "Line too big");
  603.  
  604.         /* New line if does not fit on current line */
  605.  
  606.         if (COL + tlength - 1 > LINE_LENGTH)
  607.             put_line();
  608.     }
  609.  
  610.     /* Output data with required padding */
  611.  
  612.     if (padtype == 'L')
  613.         put_blanks(width - slength);
  614.     n = slength;
  615.     while (n--) {
  616.         pchar("put_buffer",*buffer);
  617.         putc(*buffer++,IOFDESC);
  618.     }
  619.     COL += tlength;
  620.     if (padtype == 'T')
  621.         put_blanks(width - slength);
  622. }
  623.  
  624. /* OPEN_SEQ_IO */
  625.  
  626. /*  Create or open a SEQUENTIAL_IO file. If the file is to be created,
  627.  *  an AFCB is created and initialized to empty. If the file is to be opened,
  628.  *  the existing file is accessed, and the AFCB initialized for that file.
  629.  *  The argument opn is 'C' to create a file and 'O' to open a file.
  630.  */
  631.  
  632. void open_seq_io(int opn)                                        /*;open_seq*/
  633. {
  634.     DISCARD_GENERIC_PARAMETER;
  635.  
  636.     open_file();
  637.  
  638. #ifdef SYSTEM_V
  639.     if (strlen(IOFNAME) > 14) predef_raise(NAME_ERROR,"Invalid file name");
  640. #endif
  641.  
  642.     if (opn == 'C') {
  643.         IOFDESC = fopen_bin(IOFNAME, "w");
  644.         if (IOFDESC == NULL) predef_raise(NAME_ERROR,"Invalid file name");
  645.         if (IOMODE == SIO_IN_FILE) {
  646.             fclose(IOFDESC);
  647.             IOFDESC = fopen_bin(IOFNAME, "r");
  648.             check_opened_ok();
  649.         }
  650.     }
  651.     else {                      /* opn == 'O' */
  652.         IOFDESC = fopen_bin(IOFNAME, "r");
  653.         if (IOFDESC == NULL) predef_raise(NAME_ERROR,"File not found");
  654.         if (IOMODE == SIO_IN_FILE)
  655.             ;
  656.         else {
  657.             fclose(IOFDESC);
  658.             IOFDESC = fopen_bin(IOFNAME, "w");
  659.             check_opened_ok();
  660.         }
  661.     }
  662.     *get_argument_ptr(0) = filenum;
  663. }
  664.  
  665. /* OPEN_DIR_IO */
  666.  
  667. /*  Open or create a DIRECT_IO file. If the file is to be created, an
  668.  *  AFCB is created and initialized to empty. If the file is to be opened,
  669.  *  the existing file is accessed, and the AFCB initialized for that file.
  670.  *  The argument opn is 'C' to create a file and 'O' to open a file.
  671.  */
  672.  
  673. void open_dir_io(int opn)                                    /*;open_dir_io*/
  674. {
  675.     int     *item_tt_ptr;
  676.     long    eof_pos;
  677.     int     type;
  678.  
  679.     POP_PTR(item_tt_ptr);              /* pop generic type */
  680.  
  681.     type = TYPE(item_tt_ptr);
  682.     if (type == TT_U_ARRAY || type == TT_U_RECORD) {
  683.         predef_raise(USE_ERROR,
  684.           "Unconstrained types not permitted for direct IO");
  685.     }
  686.     open_file();
  687.     DLENGTH = SIZE(item_tt_ptr) * sizeof(int);
  688.  
  689. #ifdef SYSTEM_V
  690.     if (strlen(IOFNAME) > 14) predef_raise(NAME_ERROR,"Invalid file name");
  691. #endif
  692.  
  693.     if (opn == 'C') {
  694.         IOFDESC = fopen_bin(IOFNAME,"w+");
  695.         if (IOFDESC == NULL) predef_raise(NAME_ERROR,"Invalid filename");
  696.         DPOS = 1;
  697.         DSIZE = 0;
  698.     }
  699.     else {
  700.         IOFDESC = fopen_bin(IOFNAME, "r");
  701.         if (IOFDESC == NULL) predef_raise(NAME_ERROR,"File not found");
  702.         if (IOMODE == DIO_IN_FILE)
  703.             ;
  704.         else if (IOMODE == DIO_OUT_FILE) {
  705.             fclose(IOFDESC);
  706.             IOFDESC = fopen_bin(IOFNAME, "w");
  707.         }
  708.         else {
  709.             fclose(IOFDESC);
  710.             IOFDESC = fopen_bin(IOFNAME, "r+");
  711.         }
  712.         check_opened_ok();
  713.  
  714.         DPOS = 1;
  715.         fseek(IOFDESC, 0L, 2);
  716.         eof_pos = ftell(IOFDESC);
  717.         DSIZE = eof_pos / DLENGTH;
  718.     }
  719.     *get_argument_ptr(0) = filenum;
  720. }
  721.  
  722.  
  723. /* OPEN_FILE */
  724.  
  725. /*  This routine is used for all file types to perform the basic operations
  726.  *  of acquiring the parameters for an open and constructing an AFCB. On
  727.  *  return the AFCB is built and filenum references the afcbs entry set.
  728.  */
  729.  
  730. static void open_file()                                             /*;open_file*/
  731. {
  732.     int     *file_ptr;
  733.  
  734.     file_ptr = get_argument_ptr(0);
  735.     check_ifile_closed(file_ptr);
  736.  
  737.     filenum = 1;
  738.     while(afcbs[filenum - 1] != 0 && filenum < 21)
  739.         filenum++;
  740.     if (afcbs[filenum - 1] != 0)
  741.         predef_raise(USE_ERROR, "Too many files open");
  742.  
  743.     afcbs[filenum - 1] = (struct afcb  *)(predef_alloc(sizeof(struct afcb)));
  744.  
  745.     IOFDESC = NULL;
  746.  
  747.     IOMODE = get_argument_value(2);
  748.  
  749.     get_string_value(4);
  750.     IOFNAME = make_string();
  751.  
  752.     get_string_value(8);
  753.     IOFORM = make_string();
  754.  
  755.     /* Check for temporary file */
  756.  
  757.     if (*IOFNAME == '\0') {
  758.         struct tfile   *tfilep;
  759. #ifdef IBM_PC
  760.         IOFNAME = predef_alloc(L_tmpnam);
  761.         tmpnam(IOFNAME);
  762. #else
  763.         IOFNAME = predef_alloc(15);
  764.         strcpy(IOFNAME, "ADATEMP_XXXXXX");
  765.         IOFNAME = mktemp(IOFNAME);
  766. #endif
  767.         tfilep = (struct tfile *)(predef_alloc(sizeof(struct tfile)));
  768.         tfilep -> tfile_next = tfiles;
  769.         tfiles = tfilep;
  770.         strcpy(tfiles -> tfile_name, IOFNAME);
  771.     }
  772.  
  773.     /* If not temporary file, make sure it is not already open */
  774.  
  775.     else
  776.         check_xfile_closed(IOFNAME);
  777. }
  778.  
  779. /* CLOSE_FILE */
  780.  
  781. /* Close file and deallocate the AFCB */
  782.  
  783. void close_file()                                                /*;close_file*/
  784. {
  785.     fclose(IOFDESC);
  786.     predef_free(IOFNAME);
  787.     predef_free(IOFORM);
  788.     predef_free((char *)(afcbs[filenum - 1]));
  789.     afcbs[filenum - 1] = 0;
  790. }
  791.  
  792. /* PREDEF_TERM : Termination routine for Input/Output packages. */
  793.  
  794. void predef_term()                                           /*;predef_term*/
  795. {
  796.     /* close all open files except stdin and stdout */
  797.  
  798.     for (filenum = 3; filenum <= MAXFILES; filenum++) {
  799.         if (afcbs[filenum - 1] != NULL && IOFDESC != NULL) {
  800.             if (IOMODE == SIO_OUT_FILE)
  801.                 close_file();
  802.             else if (IOMODE == DIO_OUT_FILE || IOMODE == DIO_INOUT_FILE)
  803.                 close_file();
  804.             else if (IOMODE == TIO_OUT_FILE)
  805.                 close_textio();
  806.         }
  807.     }
  808.  
  809.     /* Delete temporary files upon completion of the main program */
  810.  
  811.     while(tfiles != 0) {
  812.         unlink(tfiles -> tfile_name);
  813.         tfiles = tfiles -> tfile_next;
  814.     }
  815. #ifdef IBM_PC
  816.     /* Flush input buffer if there is something there, since MS_DOS
  817.      * will retain the unwanted information for next program execution.
  818.      * Check that stdin is connected to the console and that the last
  819.      * character read from stdin is not EOF (this will be the case also
  820.      * if we have not read anything from stdin) and not LINE_FEED.
  821.      */
  822.     if ( isatty(fileno(stdin))  && 
  823.       last_char_input != EOF && last_char_input != LINE_FEED) {
  824.         filenum = 1;    /* stdin */
  825.         do {
  826.             last_char_input = fgetc(IOFDESC);
  827.         } while ( last_char_input != LINE_FEED && last_char_input != EOF);
  828.     }
  829. #endif
  830. }
  831.  
  832. /* PREDEF_ALLOC */
  833.  
  834. /* Procedure to allocate storage for use by PREDEF. The argument is the
  835.  * length of storage required in bytes. For now we allocate this storage
  836.  * on the main C heap. Later on when we extend the Ada heap to multiple
  837.  * segments, we may allocate on the Ada heap.
  838.  */
  839.  
  840. char *predef_alloc(int s)                                     /*;predef_alloc*/
  841. {
  842.     return (char *) malloc(s);
  843. }
  844.  
  845. /* Procedure to free storage previously acquired by a call to PREDEF_ALLOC */
  846.  
  847. void predef_free(char *p)                                      /*;predef_free*/
  848. {
  849.     free(p);
  850. }
  851. #ifdef IBM_PC
  852. /* if need to distinguish binary and text files */
  853.  
  854. FILE *fopen_bin(char *fname, char *fmode)                    /*;fopen_bin*/
  855. {
  856.     char mode[30];
  857.     strcpy(mode,fmode);
  858.     strcat(mode,"b");
  859.     return fopen(fname, mode);
  860. }
  861.  
  862. FILE *fopen_txt(char *fname, char *fmode)                    /*;fopen_txt*/
  863. {
  864.     char mode[30];
  865.     strcpy(mode,fmode);
  866.     strcat(mode,"t");
  867.     return fopen(fname, mode);
  868. }
  869. #endif
  870.  
  871. #ifdef DEBUG_PREDEF
  872. static int pchars=0;
  873. static int gchars=0;
  874.  
  875. static void gchar(char *msg, int c)                                    /*;gchar*/
  876. {
  877.     gchars++;
  878.     printf("\ngchar %03d %s %03d %02x ",gchars,msg,c,c);
  879.     if (c>=0 && c<32) printf("^%c",c+64);
  880.     else if (c>32 && c<127) printf(" %c",c);
  881.     else printf(" ");
  882.     printf("\n");
  883. }
  884.  
  885. static void pchar(char *msg, int c)                                    /*;pchar*/
  886. {
  887.     pchars++;
  888.     printf("\npchar %03d %s %03d %02x ",pchars,msg,c,c);
  889.     if (c>=0 && c<32) printf("^%c",c+64);
  890.     else if (c>32 && c<127) printf(" %c",c);
  891.     else printf(" ");
  892.     printf("\n");
  893. }
  894. #endif
  895.